package com.xiaoyaoji.admin.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.xiaoyaoji.admin.pojo.dto.HttpDoc;
import com.xiaoyaoji.admin.pojo.dto.HttpDocEntity;
import com.xiaoyaoji.admin.service.IDocService;
import com.xiaoyaoji.admin.service.IProjectService;
import com.xiaoyaoji.common.util.StringUtils;
import com.xiaoyaoji.postman.pojo.dto.PostmanDTO;
import com.xiaoyaoji.txt.pojo.dto.TxtDTO;
import com.xiaoyaoji.admin.pojo.enums.DocType;
import com.xiaoyaoji.admin.pojo.model.Doc;
import com.xiaoyaoji.admin.dao.mapper.DocMapper;
import com.xiaoyaoji.admin.pojo.model.Project;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoyaoji.txt.util.DocUtils;
import com.xiaoyaoji.txt.util.TxtAnalysisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author LiYaCai
 * @since 2020-06-11
 */
@Service
public class DocServiceImpl extends ServiceImpl<DocMapper, Doc> implements IDocService {

    @Autowired
    private IProjectService projectService;

    @Override
    public void importTxtDoc(String projectId, String parentId, MultipartFile file) throws Exception {

        List<TxtDTO> txtDTOList = TxtAnalysisUtils.exec(file.getInputStream());

        Project project = projectService.getById(projectId);
        Assert.notNull(project, "项目不存在");

        Doc parentDoc = this.getById(parentId);
        Assert.notNull(parentDoc, "父目录不存在");
        Assert.notNull(Objects.equals(parentDoc.getType(), DocType.SYS_FOLDER.getValue()), "父目录不是文件夹类型");
        QueryWrapper<Doc> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Doc::getParentId, parentId);
        int sort = this.count(queryWrapper);

        for (TxtDTO txt : txtDTOList) {
            Doc insertDoc = new Doc();
            String content = DocUtils.getDocContent(txt);
            insertDoc.setId(StringUtils.id())
                    .setName(txt.getTitle())
                    .setSort(sort++)
                    .setType(DocType.SYS_HTTP.getValue())
                    .setContent(content)
                    .setCreateTime(LocalDateTime.now())
                    .setLastUpdateTime(LocalDateTime.now())
                    .setParentId(parentId)
                    .setProjectId(projectId);
            insertDoc.insert();
        }

    }

    @Override
    public PostmanDTO exportPostmanJson(String parentId) {
        Doc parentDoc = this.getById(parentId);
        Assert.notNull(parentDoc, "父目录不存在");
        Assert.notNull(Objects.equals(parentDoc.getType(), DocType.SYS_FOLDER.getValue()), "父目录不是文件夹类型");
        QueryWrapper<Doc> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Doc::getParentId, parentId);
        List<Doc> docList = this.list(queryWrapper);
        Assert.notEmpty(docList, "父目录不存在接口");

        PostmanDTO postmanDTO = new PostmanDTO();
        // 目录名称
        PostmanDTO.InfoBean info = new PostmanDTO.InfoBean().setName(parentDoc.getName());
        postmanDTO.setInfo(info);

        List<PostmanDTO.ItemBean> itemList = Lists.newArrayList();
        for (Doc doc : docList) {
            if (Objects.isNull(doc.getContent())
                    || !(DocType.SYS_HTTP.getValue().equalsIgnoreCase(doc.getType())
                    || DocType.SYS_WEBSOCKET.getValue().equalsIgnoreCase(doc.getType()))) {
                continue;
            }
            PostmanDTO.ItemBean item = new PostmanDTO.ItemBean();
            PostmanDTO.ItemBean.RequestBean request = new PostmanDTO.ItemBean.RequestBean();
            HttpDoc httpDoc = JSONObject.parseObject(doc.getContent(), HttpDoc.class);
            String requestMethod = httpDoc.getRequestMethod();
            request.setMethod(requestMethod);
            PostmanDTO.ItemBean.RequestBean.UrlBean url = new PostmanDTO.ItemBean.RequestBean.UrlBean();
            url.setPath(httpDoc.getUrl());
            if ("get".equalsIgnoreCase(requestMethod)) {
                List<PostmanDTO.ItemBean.RequestBean.UrlBean.QueryBean> queryList = Lists.newArrayList();
                List<HttpDocEntity> requestArgs = httpDoc.getRequestArgs();
                for (HttpDocEntity requestArg : requestArgs) {
                    PostmanDTO.ItemBean.RequestBean.UrlBean.QueryBean query = new PostmanDTO.ItemBean.RequestBean.UrlBean.QueryBean();
                    query.setKey(requestArg.getName());
                    query.setValue(requestArg.getDefaultValue());
                    queryList.add(query);
                }
                url.setQuery(queryList);
            }
            request.setUrl(url);
            if (!"get".equalsIgnoreCase(requestMethod)) {
                PostmanDTO.ItemBean.RequestBean.BodyBean body = new PostmanDTO.ItemBean.RequestBean.BodyBean();
                List<HttpDocEntity> requestArgs = httpDoc.getRequestArgs();
                JSONObject jsonObject = requestArgs2JsonObject(requestArgs);
                body.setRaw(JSONObject.toJSONString(jsonObject,
                        new SerializerFeature[]{
                                SerializerFeature.WriteMapNullValue,
                                SerializerFeature.WriteNullListAsEmpty
                        })
                        .replace("\\", ""));
                body.setOptions(new PostmanDTO.ItemBean.RequestBean.BodyBean.OptionsBean());
                request.setBody(body);
            }
            item.setName(doc.getName()).setRequest(request);
            itemList.add(item);
        }
        // 接口
        postmanDTO.setItem(itemList);

        return postmanDTO;
    }

    @Override
    public String getResponseJson(String id) {
        Doc doc = this.getById(id);
        Assert.notNull(doc, "接口文档不存在");
        Assert.notNull(Objects.equals(doc.getType(), DocType.SYS_HTTP.getValue()), "接口文档不是http 接口类型");

        HttpDoc httpDoc = JSONObject.parseObject(doc.getContent(), HttpDoc.class);
        List<HttpDocEntity> responseArgs = httpDoc.getResponseArgs();

        for (HttpDocEntity arg : responseArgs) {
            if(Objects.isNull(arg.getName()) || !Objects.equals(arg.getName(), "data")) {
                continue;
            }
            JSONObject jsonObject = responseArgs2JsonObject(arg.getChildren());
            return JSONObject.toJSONString(jsonObject, SerializerFeature.WriteNullListAsEmpty)
                    .replace("\\", "");
        }
        return null;
    }

    private JSONObject requestArgs2JsonObject(List<HttpDocEntity> docEntityList) {
        if(CollectionUtils.isEmpty(docEntityList)) {
            return null;
        }
        JSONObject jsonObject = new JSONObject();
        for (HttpDocEntity docEntity : docEntityList) {
            switch (docEntity.getType()) {
                case "number":
                case "boolean":
                case "string":
                case "file":
                    jsonObject.put(docEntity.getName(), null);
                    break;
                case "object":
                    jsonObject.put(docEntity.getName(), requestArgs2JsonObject(docEntity.getChildren()));
                    break;
                case "array[object]":
                    jsonObject.put(docEntity.getName(), Lists.newArrayList(requestArgs2JsonObject(docEntity.getChildren())));
                    break;
                case "array[number]":
                case "array[boolean]":
                case "array[string]":
                case "array":
                case "array[array]":
                    jsonObject.put(docEntity.getName(), Lists.newArrayList());
                    break;
                default:
                    break;
            }
        }
        return jsonObject;
    }

    private JSONObject responseArgs2JsonObject(List<HttpDocEntity> docEntityList) {
        if(CollectionUtils.isEmpty(docEntityList)) {
            return null;
        }
        JSONObject jsonObject = new JSONObject();
        for (HttpDocEntity docEntity : docEntityList) {
            switch (docEntity.getType()) {
                case "number":
                    jsonObject.put(docEntity.getName(), 0);
                    break;
                case "boolean":
                    jsonObject.put(docEntity.getName(), false);
                    break;
                case "string":
                    jsonObject.put(docEntity.getName(), "");
                    break;
                case "file":
                    jsonObject.put(docEntity.getName(), null);
                    break;
                case "object":
                    jsonObject.put(docEntity.getName(), responseArgs2JsonObject(docEntity.getChildren()));
                    break;
                case "array[object]":
                    jsonObject.put(docEntity.getName(), Lists.newArrayList(responseArgs2JsonObject(docEntity.getChildren())));
                    break;
                case "array[number]":
                    jsonObject.put(docEntity.getName(), new ArrayList<Integer>());
                    break;
                case "array[boolean]":
                    jsonObject.put(docEntity.getName(), new ArrayList<Boolean>());
                    break;
                case "array[string]":
                    jsonObject.put(docEntity.getName(), new ArrayList<String>());
                    break;
                case "array":
                case "array[array]":
                    jsonObject.put(docEntity.getName(), Lists.newArrayList());
                    break;
                default:
                    break;
            }
        }
        return jsonObject;
    }

}
